import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppRoutingModule} from './app-routing.module';
import {
  GnAppConfigModule,
  GnAppRootComponent,
  GnAppRootModule,
  GnHttpInterceptorConfig,
  GnLoginUser,
  GnMessageService,
  GnRouteGuard,
  GnSiteInfo
} from 'geminis-ng';
import {HttpClient} from '@angular/common/http';
import {Router} from '@angular/router';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {PortalLayoutModule} from './layout/layout.module';
import {NZ_CONFIG, NzConfig} from 'ng-zorro-antd/core/config';
import {OAuthModule} from './oidc/oauth.module';
import {addGlobalUncaughtErrorHandler, registerMicroApps, start} from 'qiankun';

const nzZorroConfig: NzConfig = {
  modal: {nzMaskClosable: false}
};

@NgModule({
  declarations: [],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,

    GnAppRootModule,
    GnAppConfigModule,
    PortalLayoutModule,

    OAuthModule
  ],
  providers: [
    {provide: NZ_CONFIG, useValue: nzZorroConfig}
  ],
  bootstrap: [GnAppRootComponent]
})
export class AppModule {

  constructor(private router: Router,
              private loginUser: GnLoginUser,
              private siteInfo: GnSiteInfo,
              private routeGuard: GnRouteGuard,
              private httpInterceptorConfig: GnHttpInterceptorConfig,
              private messageService: GnMessageService,
              private http: HttpClient) {

    this.siteInfo.loginUrl = '/login';
    this.httpInterceptorConfig.startWithUrl = '/api/';
    this.httpInterceptorConfig.ignoreUrls = ['/api/resources/oauth/token'];

    this.shareToken();
    this.loadLoginUser();
    this.initMicroService();
  }

  private loadLoginUser(): void {
    const loginUserValue = sessionStorage.getItem('LoginUser');
    if (loginUserValue) {
      Object.assign(this.loginUser, JSON.parse(loginUserValue));
    } else {
      localStorage.setItem('geminiGetToken', Math.random().toString(10));
      localStorage.setItem('geminiGetAuth', Math.random().toString(10));
    }
  }

  private shareToken(): void {
    window.addEventListener('storage', (event) => {
      if (!event.newValue) {
        return;
      }
      if (event.key === 'geminiSetToken') {
        sessionStorage.setItem('LoginUser', event.newValue);
        this.loadLoginUser();
      } else if (event.key === 'geminiGetToken') {
        const loginUserValue = sessionStorage.getItem('LoginUser');
        if (loginUserValue) {
          localStorage.setItem('geminiSetToken', loginUserValue);
          localStorage.removeItem('geminiSetToken');
        }
      } else if (event.key === 'geminiSetAuth') {
        sessionStorage.setItem('Authorization', event.newValue);
      } else if (event.key === 'geminiGetAuth') {
        const authorization = sessionStorage.getItem('Authorization');
        if (authorization) {
          localStorage.setItem('geminiSetAuth', authorization);
          localStorage.removeItem('geminiSetAuth');
        }
      }
    });
  }

  private initMicroService(): void {

    addGlobalUncaughtErrorHandler((event: Event | string): void => {
      console.error(event);
      const {message: msg} = event as any;
      // 加载失败时提示
      if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
        this.messageService.error('微服务加载失败，请检查应用是否可运行');
      }
    });

    this.http.get('assets/config/services.json')
      .subscribe((services: any) => {
          services.forEach(service => {
            service.props = {
              loginUser: this.loginUser,
              siteInfo: this.siteInfo,
              routeGuard: this.routeGuard,
              httpInterceptorConfig: this.httpInterceptorConfig,
              zorroConfig: nzZorroConfig
            };
          });
          registerMicroApps(
            services,
            {
              // qiankun 生命周期钩子 - 加载前
              beforeLoad: (app: any): Promise<void> => {
                console.log('before load', app.name);
                return Promise.resolve();
              },
              // qiankun 生命周期钩子 - 挂载后
              afterMount: (app: any): Promise<void> => {
                console.log('after mount', app.name);
                return Promise.resolve();
              },
            },
          );

          start({
            prefetch: false
          });
        },
        error => {
          this.messageService.error('获取微服务配置失败');
          console.error(error);
        });
  }
}
